/**
  ******************************************************************************
  * @file           
  * @author         古么宁
  * @brief          IEC10x 文件传输相关部分
  * @note           此文件提供 linux 平台下的文件操作接口，如需移植
  *                 需要用户实现以下接口
  ******************************************************************************
  *
  * COPYRIGHT(c) 2019 GoodMorning
  *
  ******************************************************************************
  */
/* Includes ---------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>    // for O_RDONLY

#include "iec_sys.h"
#include "iec_file.h"

/* Private types ------------------------------------------------------------*/

/* Private macro ------------------------------------------------------------*/

/// 基准文件夹地址
//#define IEC_BASE_DIR  "/home/"

/* Private variables --------------------------------------------------------*/

static const char IEC_BASE_DIR[] =  "/home/" ;

/* Global  variables --------------------------------------------------------*/

/* Private function prototypes ----------------------------------------------*/

/* Gorgeous Split-line ------------------------------------------------------*/



/**
  * @author   古么宁
  * @brief    创建多级文件夹
  * @param    path    文件夹路径
  * @return   成功返回 0 ，文件夹名过长返回 -2 ，创建失败返回 -1
*/
int iec_mkdirs(const char * path)
{
	char dirpath[128] = {0};
	char *dst = dirpath;
	char *src = (char *)path;

	int len = strlen(path);
	if (len > sizeof(dirpath)-4) {
		return -2;
	}

	while( *src ) {
		*dst++ = *src++;
		if (*src == '/' || *src == '\0') {
			if (0 == access(dirpath,0)) {
				continue;
			}
			
			if (0 != mkdir(dirpath,0755)) {
				return -1;
			}
		}
	}

	return 0;
}

/**
  * @author   古么宁
  * @brief    iec 打开文件夹
  * @param    dirname  : 目标文件夹名称
  * @return   成功返回打开文件夹的句柄，否则返回 NULL
*/
iec_dir_t * iec_opendir(const char * dirname)
{
	iec_dir_t * newdir = iec_malloc(sizeof(iec_dir_t));
	if (newdir == NULL){
		return NULL;
	}

	sprintf(newdir->path, "%s%s",IEC_BASE_DIR,dirname);
	newdir->fd = opendir(newdir->path);

	if (NULL == newdir->fd) {
		iec_free(newdir);
		return NULL;
	}
	
	return newdir;
}



/**
  * @author   古么宁
  * @brief    iec 关闭文件夹
  * @param    dir   : 目标文件夹句柄
  * @return   
*/
int iec_closedir(iec_dir_t * dir)
{
	closedir(dir->fd);
	iec_free(dir);
	return 0;
}



/**
  * @author   古么宁
  * @brief    iec 读取一次文件夹内容
  * @param    dir      : 已打开的文件夹
  * @param    filename : 当前次读取到的文件名
  * @param    filetime : 文件最后修改时间
  * @return   成功返回文件长度，返回 -1 表示已结束读取
*/
int iec_readdir(iec_dir_t *dir , char * filename , struct CP56Time2a * filetime)
{
	struct dirent * dirdata;
	struct stat fstat;
	struct tm ftime;
	char path[256] ;
	int sec;

restart:
	dirdata = readdir(dir->fd);
	if (NULL == dirdata) {
		return -1;
	}

	/* 此处过滤文件夹选项，即仅返回可用文件内容，不返回子文件夹内容 */
	if (dirdata->d_type & DT_DIR) {
		printf("sub directory:%s\r\n", dirdata->d_name);
		goto restart ;
	}

	/* 生成文件的绝对路径 */
	sprintf(path,"%s/%s",dir->path,dirdata->d_name);
	strcpy(filename,dirdata->d_name);

	/* 获取文件状态信息 */
	if (stat(path,&fstat) < 0) {
		printf("cannot get file stat : %s\r\n",path);
		return -1;
	}

	/* 获取文件时间 */
	localtime_r(&fstat.st_mtime, &ftime);

	/* CP56Time2a 的年份以 2000 为起点，struct tm 的年份以 1900 为起点 */
	filetime->year        = ftime.tm_year - 100; 
	filetime->month       = ftime.tm_mon + 1;
	filetime->day.date    = ftime.tm_mday   ;
	filetime->day.weekday = ftime.tm_wday   ;
	filetime->hour        = ftime.tm_hour   ;
	filetime->min         = ftime.tm_min    ;

	sec = ftime.tm_sec * 1000;
	filetime->ms[0] = sec & 0x00ff;
	filetime->ms[1] = (sec >> 8) & 0xff;

	return fstat.st_size;
}




/**
  * @author   古么宁
  * @brief    iec 打开一个文件
  * @param    dir      : 指定读取文件夹
  * @param    file     : 文件名
  * @param    mode     : 'r' or 'w' : read/write
  * @return   成功返回文件句柄
*/
iec_file_t * iec_fopen(const char * dir , const  char * file , int mode)
{
	iec_file_t * iecfile = NULL;
	char path[256];
	int base_dir_len  = sizeof(IEC_BASE_DIR) - 1 ;
	int dir_len = strlen(dir);
	int fname_len = strlen(file);
	int len = base_dir_len + dir_len + fname_len;
	int fd ;

	if (len > sizeof(path) - 3) {
		return NULL;
	}

	/* 拼凑全绝对路径，文件夹不存在则创建文件夹 */
	sprintf(path,"%s%s",IEC_BASE_DIR,dir);
	if (access(path,0) < 0) {
		if (iec_mkdirs(path) < 0) {
			printf("create directory failed!\n");
			return NULL;
		}
		else {
			printf("create directory successfully!\n");
		}
	}

	/* 拼凑全绝对路径 */
	len = base_dir_len + dir_len;
	path[len++] = '/';
	memcpy(&path[len],file,fname_len);
	path[len+fname_len] = '\0';

	if ('r' == mode) {
		fd = open(path, O_RDONLY);
	}
	else {
		fd = open(path, O_WRONLY|O_CREAT,0777);
	}

	if (fd < 0) {
		return NULL;
	}

	iecfile = malloc(sizeof(iec_file_t));
	if (NULL == iecfile) {
		return NULL;
	}

	iecfile->fd = fd;
	return iecfile;
}



/**
  * @author   古么宁
  * @brief    iec 读取文件内容
  * @param    iecfile  : 已打开的文件句柄
  * @param    ptr      : 文件内存
  * @param    size     : 当前次读取大小
  * @return   成功返回文件读取长度，错误返回小于 0
*/
int iec_fread(iec_file_t *iecfile, void * ptr , size_t size)
{
	return read(iecfile->fd, ptr, size);
}



/**
  * @author   古么宁
  * @brief    iec 写入文件内容
  * @param    iecfile  : 已打开的文件句柄
  * @param    ptr      : 文件内存
  * @param    size     : 当前次读取大小
  * @return   成功返回文件读取长度，错误返回小于 0
*/
int iec_fwrite(iec_file_t *iecfile, void * ptr , size_t size)
{
	return write(iecfile->fd, ptr, size);
}


/**
  * @author   古么宁
  * @brief    iec 关闭文件
  * @param    iecfile  : 已打开的文件句柄
  * @return   成功返回 0
*/
int iec_fclose(iec_file_t *iecfile)
{
	int fd = iecfile->fd;
	free(iecfile);
	return close(fd);
}


/**
  * @author   古么宁
  * @brief    iec 获取文件大小
  * @param    dir      : 指定读取文件夹
  * @param    file     : 文件名
  * @return   成功返回文件读取长度，错误返回小于 0
*/
int iec_fsize(const char * dir , const char * file)
{
	struct stat fstat;
	char path[256] ;
	sprintf(path,"%s%s/%s",IEC_BASE_DIR,dir,file);

	/* 获取文件状态信息 */
	if (stat(path,&fstat) < 0) {
		printf("cannot get file stat : %s\r\n",path);
		return -1;
	}

	return fstat.st_size;
}

